//! DES加密实现
//! 
//! 提供DES加密解密功能

use des::Des;
use des::cipher::{BlockEncrypt, BlockDecrypt, KeyInit, generic_array::GenericArray};
use rand::RngCore;
use base64::{Engine as _, engine::general_purpose};

/// DES错误类型
#[derive(Debug, thiserror::Error)]
pub enum DESError {
    #[error("Invalid key length: {0}")]
    InvalidKeyLength(String),
    #[error("DES encryption failed: {0}")]
    EncryptionFailed(String),
    #[error("DES decryption failed: {0}")]
    DecryptionFailed(String),
    #[error("Base64 decode error: {0}")]
    Base64Error(#[from] base64::DecodeError),
}

pub type DESResult<T> = Result<T, DESError>;

/// DES加密
/// 
/// # Examples
/// ```
/// use librarys::crypto::symmetric::des_encrypt;
/// 
/// let key = b"12345678"; // 8字节密钥
/// let plaintext = "hello world";
/// let encrypted = des_encrypt(plaintext, key).unwrap();
/// assert!(!encrypted.is_empty());
/// ```
pub fn des_encrypt(plaintext: &str, key: &[u8]) -> DESResult<String> {
    if key.len() != 8 {
        return Err(DESError::InvalidKeyLength(format!("DES key must be 8 bytes, got {}", key.len())));
    }
    
    let cipher = Des::new(GenericArray::from_slice(key));
    let plaintext_bytes = plaintext.as_bytes();
    
    // 添加PKCS7填充
    let mut padded_data = plaintext_bytes.to_vec();
    let padding_len = 8 - (plaintext_bytes.len() % 8);
    if padding_len != 8 {
        for _ in 0..padding_len {
            padded_data.push(padding_len as u8);
        }
    }
    
    let mut encrypted_data = Vec::new();
    
    // 逐块加密
    for chunk in padded_data.chunks(8) {
        let mut block = GenericArray::clone_from_slice(chunk);
        cipher.encrypt_block(&mut block);
        encrypted_data.extend_from_slice(&block);
    }
    
    Ok(general_purpose::STANDARD.encode(encrypted_data))
}

/// DES解密
/// 
/// # Examples
/// ```
/// use librarys::crypto::symmetric::{des_encrypt, des_decrypt};
/// 
/// let key = b"12345678"; // 8字节密钥
/// let plaintext = "hello world";
/// let encrypted = des_encrypt(plaintext, key).unwrap();
/// let decrypted = des_decrypt(&encrypted, key).unwrap();
/// assert_eq!(decrypted, plaintext);
/// ```
pub fn des_decrypt(ciphertext: &str, key: &[u8]) -> DESResult<String> {
    if key.len() != 8 {
        return Err(DESError::InvalidKeyLength(format!("DES key must be 8 bytes, got {}", key.len())));
    }
    
    let cipher = Des::new(GenericArray::from_slice(key));
    let encrypted_data = general_purpose::STANDARD.decode(ciphertext)?;
    
    if encrypted_data.len() % 8 != 0 {
        return Err(DESError::DecryptionFailed("Invalid ciphertext length".to_string()));
    }
    
    let mut decrypted_data = Vec::new();
    
    // 逐块解密
    for chunk in encrypted_data.chunks(8) {
        let mut block = GenericArray::clone_from_slice(chunk);
        cipher.decrypt_block(&mut block);
        decrypted_data.extend_from_slice(&block);
    }
    
    // 移除PKCS7填充
    if let Some(&padding_len) = decrypted_data.last() {
        if padding_len > 0 && padding_len <= 8 {
            let data_len = decrypted_data.len();
            if data_len >= padding_len as usize {
                decrypted_data.truncate(data_len - padding_len as usize);
            }
        }
    }
    
    String::from_utf8(decrypted_data)
        .map_err(|e| DESError::DecryptionFailed(format!("Invalid UTF-8: {}", e)))
}

/// 生成随机DES密钥
/// 
/// # Examples
/// ```
/// use librarys::crypto::symmetric::generate_des_key;
/// 
/// let key = generate_des_key();
/// assert_eq!(key.len(), 8);
/// ```
pub fn generate_des_key() -> [u8; 8] {
    let mut key = [0u8; 8];
    rand::thread_rng().fill_bytes(&mut key);
    key
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_des_encrypt_decrypt() {
        let key = b"12345678";
        let plaintext = "hello world";
        
        let encrypted = des_encrypt(plaintext, key).unwrap();
        assert!(!encrypted.is_empty());
        
        let decrypted = des_decrypt(&encrypted, key).unwrap();
        assert_eq!(decrypted, plaintext);
    }

    #[test]
    fn test_des_key_generation() {
        let key = generate_des_key();
        assert_eq!(key.len(), 8);
        
        // 生成两个密钥应该不同
        let key2 = generate_des_key();
        assert_ne!(key, key2);
    }

    #[test]
    fn test_des_invalid_key_length() {
        let result = des_encrypt("test", b"short");
        assert!(result.is_err());
        
        let result = des_decrypt("test", b"short");
        assert!(result.is_err());
    }

    #[test]
    fn test_des_empty_string() {
        let key = b"12345678";
        let plaintext = "";
        
        let encrypted = des_encrypt(plaintext, key).unwrap();
        let decrypted = des_decrypt(&encrypted, key).unwrap();
        assert_eq!(decrypted, plaintext);
    }
}